﻿//Copyright (C) <2013>  <jonathan cleeve norton> All Rights Reserved 
//Contact jon.norton@fin-plus.co.uk website <http://www.fin-plus.co.uk/>
using System;
using FinPlusAssembler;
using FinPlusInterfaces;

namespace FinPlusCompCore
{
    public class PermissionService : FinPlusComponent, IPPodManager 
    {
        [State(Test = true)]
        public override bool IsValid { get; set; }
        private IGPods _groups;
        private volatile static IPPods _permissions;
        private volatile static Object _lock = new Object();
        private IPPod _envPerm, _configPerm, _groupPerm;
        private string _configType;

        //construct
        public PermissionService(string configType, string config, Env env) 
        {
            _configType = configType;
            Config = config;
            Env = env;
        }

        //public
        public IPPod Get(string type, string name, string value = null)
        {
            try
            {
                if (value == null) 
                    value = name;

                GetPerms();
                GetGroups();

                //layer 4 pod 
                var perm = value.Equals("-1") ? IOC.New<IPPod>(true, true) : _permissions.Get(User, type, name, value);

                //layer 3 group 
                if (type.Equals(Common.Group.ToString()) || type.Equals(Common.Environment.ToString()) || type.Equals(Common.ClientConfig.ToString()) || type.Equals(Common.ServiceConfig.ToString()))
                    _groupPerm = perm;
                else if (_groups.ContainsKey(type))
                    _groupPerm = _permissions.Get(User, Common.Group.ToString(), _groups[type], _groups[type]);
                else
                    _groupPerm = IOC.New<IPPod>(false, false);

                //layer 2 app
                if (_configPerm == null)
                    _configPerm = _permissions.Get(User, _configType, Config, Config);

                //layer 1 environment 
                if (_envPerm == null)
                    _envPerm = _permissions.Get(User, Common.Environment.ToString(), Env.ToString(), Env.ToString());

                return _envPerm.Add(_configPerm.Add(_groupPerm.Add(perm)));
            }
            catch (Exception e)
            {
                throw new PodException(string.Format("failed to get permissions {0} {1} {2}", type, name, value), e);
            }
        }

        public IPPod Get(IDPod value)
        {
            try
            {
                object name, id;

                if (value.TryGetObject(PodField.Type.ToString(), out name) && value.TryGetObject(PodField.Id.ToString(), out id))
                    return Get(name.ToString(), PodField.Id.ToString(), id.ToString());

                return IOC.New<IPPod>(false, false);
            }
            catch (Exception e)
            {
                throw new PodException(string.Format("failed to get permissions {0}", value.ToString()), e);
            }
        }

        public IPPod Get(IDPod value, string name)
        {
            try
            {
                object id;
                if (!value.TryGetObject(PodField.Id.ToString(), out id))
                    return IOC.New<IPPod>(false, false);

                return Get(name, PodField.Id.ToString(), id.ToString());
            }
            catch (Exception e)
            {
                throw new PodException(string.Format("failed to get permissions {0}", value.ToString()), e);
            }
        }

        //private
        private void GetPerms()
        {
            if (_permissions == null)
                lock (_lock)
                    if (_permissions == null)
                    {
                        var conn = new FinPlusConnectService("Perm", "Query", "[group],Security;[type],Select;[where],Name='User' And Value='" + User + "';env,dev;", User);
                        _permissions = IOC.New<IPPods>(conn.Adapter);
                    }
        }

        private void GetGroups()
        {
            if (_groups == null)
                lock (_lock)
                    if (_groups == null)
                    {
                         var conn = new FinPlusConnectService("Groups", "Query", "[group],PodMap;[type],Select;[where];,[env],dev;", User);
                        _groups = IOC.New<IGPods>(conn.Adapter);
                    }
        }
    }
}
